﻿#include "client.h"
#include "ui_client.h"
#include <iostream>
#include <QThread>
//#include <opencv2/highgui/highgui.hpp>
//#include <opencv2/imgproc/imgproc.hpp>
//#include <opencv2/core/core.hpp>

Client::Client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Client)
{
    ui->setupUi(this);

    ui->Text_ip->setText("192.168.0.10");
    ui->Text_port->setText("60000");

    messenger = new Messenger();
    connect(messenger, SIGNAL(onConnectServer()), this, SLOT(onTcpConnected()));//若已与服务器连接，则打开指令按钮
    connect(messenger,SIGNAL(onDisconnectServer()),this,SLOT(onTcpBreak()));

    setButtonEnable(this, false);
    ui->speedBox->addItems(QStringList()<<QString::fromLocal8Bit("慢")<<QString::fromLocal8Bit("中")<<QString::fromLocal8Bit("快"));
    ui->pattern->addItems(QStringList()<<QString::fromLocal8Bit("点控模式")<<QString::fromLocal8Bit("联动模式"));
    ui->motoBox->addItems(QStringList()<<"1"<<"2"<<"3"<<"4");

    ui->spinBox_1->setRange(1, 10);
    ui->spinBox_2->setRange(1, 10);
    ui->spinBox_3->setRange(1, 10);
    ui->spinBox_4->setRange(1, 10);

    ui->progressBar->setRange(0,100);
    ui->progressBar->setValue(0);
}

Client::~Client()
{
    delete ui;
}

void Client::setButtonEnable(QObject*object,bool flag){
    for(QObject* o : object->children()){
        setButtonEnable(o,flag);
        if((o->inherits("QPushButton") && o->objectName() != "Button_Connect"))
            qobject_cast<QPushButton*>(o)->setEnabled(flag);
        if(o->inherits("QComboBox"))
            qobject_cast<QComboBox*>(o)->setEnabled(flag);
    }
}


void Client::onTcpConnected()//恢复指令按钮
{
    setButtonEnable(this,true);
}

void Client::onTcpBreak(){
    setButtonEnable(this,false);
}

int Client::BinToInt(const QString &array) {
    int len = array.size();
    int res = 0;
    for(int i = len - 1, j = 0;i >= 0;--i, ++j)
        res |= ((array[i].toLatin1() - '0') << j);
    return res;
}

void Client::on_Button_ARM_Red_clicked()
{
    messenger->write(QString("ARMledr").toUtf8());
}

void Client::on_Button_Connect_clicked()
{
    QString m_ip = ui->Text_ip->text();
    quint16 m_port = ui->Text_port->text().toInt();
    if(m_ip.size() != 0 && m_port != 0)
        messenger->ConnectServer(m_ip,m_port);
}

void Client::on_Button_Break_clicked()
{
    if(messenger->isOpen())
        messenger->DisconnectServer();
}

void Client::on_Button_ARM_Green_clicked()
{
    messenger->write(QString("ARMledg").toUtf8());
}

void Client::on_Button_ARM_Blue_clicked()
{
    messenger->write(QString("ARMledb").toUtf8());
}

void Client::on_Button_FPGA_RED_clicked()
{
    QString send = "FPGA";
    int num = BinToInt(CMD_FPGA_R + QString(12, '0'));
    send.append(QString::number(num));
    messenger->writeAndPromise(send.toUtf8(), num);
}

void Client::on_Button_FPGA_GREEN_clicked()
{
    QString send = "FPGA";
    int num = BinToInt(CMD_FPGA_G + QString(12, '0'));
    send.append(QString::number(num));
    messenger->writeAndPromise(send.toUtf8(), num);
}

void Client::on_Button_FPGA_BLUE_clicked()
{
    QString send = "FPGA";
    int num = BinToInt(CMD_FPGA_B + QString(12, '0'));
    send.append(QString::number(num));
    messenger->writeAndPromise(send.toUtf8(), num);
}

static QString moto[4] = {"00", "01", "10", "11"};//分别表示几号电机

void Client::on_Button_TAIDA_GO_pressed()
{
    if(ui->pattern->currentText() == QString::fromLocal8Bit("点控模式")){
        QString send = "FPGA";
        QString key = CMD_TAIDA_GO + QString(10, '0');
        int n = ui->motoBox->currentText().front().toLatin1() - '1';//几号电机
        key.append(moto[n]);
        int num = BinToInt(key);
        send.append(QString::number(num));
        messenger->writeAndPromise(send.toUtf8(), num);
    }
}
void Client::on_Button_TAIDA_GO_released()
{
    if(ui->pattern->currentText() == QString::fromLocal8Bit("点控模式")){
        QString send = "FPGA";
        QString key = CMD_STOP + QString(10, '0');
        int n = ui->motoBox->currentText().front().toLatin1() - '1';//几号电机
        key.append(moto[n]);
        int num = BinToInt(key);
        send.append(QString::number(num));
        messenger->writeAndPromise(send.toUtf8(), num);
    }
}

void Client::on_Button_TAIDA_BACK_pressed()
{
    if(ui->pattern->currentText() == QString::fromLocal8Bit("点控模式")){
        QString send = "FPGA";
        QString key = CMD_TAIDA_BACK + QString(10, '0');
        int n = ui->motoBox->currentText().front().toLatin1() - '1';//几号电机
        key.append(moto[n]);
        int num = BinToInt(key);
        send.append(QString::number(num));
        messenger->writeAndPromise(send.toUtf8(), num);
    }
}

void Client::on_Button_TAIDA_BACK_released()
{
    if(ui->pattern->currentText() == QString::fromLocal8Bit("点控模式")){
        QString send = "FPGA";
        QString key = CMD_STOP + QString(10, '0');
        int n = ui->motoBox->currentText().front().toLatin1() - '1';//几号电机
        key.append(moto[n]);
        int num = BinToInt(key);
        send.append(QString::number(num));
        messenger->writeAndPromise(send.toUtf8(), num);
    }
}

void Client::on_speedBox_currentTextChanged(const QString &arg1)
{
    if(!messenger->isOpen())
        return;
    QString send = "FPGA";
    int num = 0;
    if(arg1 == QString::fromLocal8Bit("慢")){
        num = BinToInt(CMD_SLOW + QString(12, '0'));
        send.append(QString::number(num));
    }else if(arg1 == QString::fromLocal8Bit("中")){
        num = BinToInt(CMD_MID + QString(12, '0'));
        send.append(QString::number(num));
    }else if(arg1 ==  QString::fromLocal8Bit("快")){
        num = BinToInt(CMD_FAST + QString(12, '0'));
        send.append(QString::number(num));
    }
    messenger->writeAndPromise(send.toUtf8(), num);
}

void Client::on_pattern_currentTextChanged(const QString &arg1)
{
    if(!messenger->isOpen())return;
    QString send = "FPGA";
    int num = 0;
    if(arg1 == QString::fromLocal8Bit("点控模式")){
        num = BinToInt(CMD_TOUCH + QString(12, '0'));
        send.append(QString::number(num));
    }else if(arg1 == QString::fromLocal8Bit("联动模式")){
        num = BinToInt(CMD_LINKMOVE + QString(12, '0'));
        send.append(QString::number(num));
    }
    messenger->writeAndPromise(send.toUtf8(), num);
}

int Client::DistanceToPlusCount(double x){//毫米转换为脉冲数
    return x * 4000 + 0.5;
}


QString Client::IntToBin(int x){
    QString res = QString::number(x,2);//2进制字符串
    if(res.size() < 16)
        res = QString(16 - res.size(), '0') + res;
    return res;
}

//unsigned int 32位   1111    1111    1111    1111    1111    1111    1111    1111  最大值 4,294,967,295个脉冲 -> 1,073,741毫米 -> 1073米
//16位   1111            1111            1111    1111
/*       0111(1号电机)    0000(第一个8位)
 *       0101(2号电机)    0100（第2个8位）
 *       1001(3号电机)    1000
 *       1101(4号电机)    1100
 *                       1111（4个8位发完了）
 *       101(开始运动)
*/
static QString direction = "000";
static QString hash[4] = {"001", "010", "011", "100"};//表示32位unsigned int 的第几个8位
static QString over = "101";

/*
 * 5毫米 20000个脉冲 0100 1110 0010 0000
 * 10毫米 40000个脉冲 1001 1100 0100 0000
*/

// 2 6
// 3 7.5

void Client::SendPlusCount(std::vector<int>steps, std::vector<QString> direct){
    QString key;
    int target;
    QString send;
    for(int i = 0;i < steps.size();++i){
        QString data = IntToBin(steps[i]);//16位2进制

        key = CMD_PLUSCOUNT + moto[i] + direction + direct[i] + QString(6, '0');
        target = BinToInt(key);
        send = "FPGA" + QString::number(target);
        messenger->writeAndPromise(send.toUtf8(), target);

        for(int j = 0;j < 4;++j){//将一个unsigned int 分4次发送
            key = CMD_PLUSCOUNT + moto[i] + hash[j] + QString(3, '0') + data.mid(j * 4, 4);
            target = BinToInt(key);
            send = "FPGA" + QString::number(target);
            messenger->writeAndPromise(send.toUtf8(), target);
        }
        //通知发完了，把四个拼起来
        key = CMD_PLUSCOUNT + moto[i] + over + QString(7, '0');
        target = BinToInt(key);
        send = "FPGA" + QString::number(target);
        messenger->writeAndPromise(send.toUtf8(), target);
    }
}

void Client::SendFreqCount(std::vector<int> freqcount){
    QString key;
    int target;
    QString send;
    for(int i = 0;i < freqcount.size();++i){
        QString data = IntToBin(freqcount[i]);//32位2进制
        for(int j = 0;j < 4;++j){//将一个unsigned int 分4次发送
            key = CMD_FREQCOUNT + moto[i] + hash[j] + QString(3, '0') + data.mid(j * 4, 4);//中间这个1表示正转
            target = BinToInt(key);
            send = "FPGA" + QString::number(target);
            messenger->writeAndPromise(send.toUtf8(), target);
        }
        //通知发完了，把四个拼起来
        key = CMD_FREQCOUNT + moto[i] + over + QString(7, '0');
        target = BinToInt(key);
        send = "FPGA" + QString::number(target);
        messenger->writeAndPromise(send.toUtf8(), target);
    }
}

void Client::SendMove(){
    QString key;
    int target;
    QString send;
    key = CMD_MOVE + QString(12, '0');
    target = BinToInt(key);
    send = "FPGA" + QString::number(target);//开始运动
    messenger->writeAndPromise(send.toUtf8(), target);
}

#include <numeric>

std::vector<int> GetFreqCount(std::vector<int> lens){//输入每个杆的运动长度，输出频率计数
    int lcm_v = lens[0];
    for(size_t i = 1;i < lens.size();++i)
        lcm_v = std::lcm(lcm_v, lens[i]);
    std::vector<int>res;
    for(int n : lens)
        res.push_back(lcm_v / n);
    for(int n : res){
        if(n == 1){//判断频率计数是否有1
            for(int& nn : res)
                nn *= 2;
            break;
        }
    }
    return res;
}

void Client::on_linkmove_clicked()
{
    //分别表示运动多少毫米，4000脉冲1毫米
    std::vector<int> steps = {DistanceToPlusCount(ui->spinBox_1->value()),
                              DistanceToPlusCount(ui->spinBox_2->value()),
                              DistanceToPlusCount(ui->spinBox_3->value()),
                              DistanceToPlusCount(ui->spinBox_4->value())};
    std::vector<QString> directions = {
        ui->checkBox_1->isChecked() ? "1" : "0",
        ui->checkBox_2->isChecked() ? "1" : "0",
        ui->checkBox_3->isChecked() ? "1" : "0",
        ui->checkBox_4->isChecked() ? "1" : "0"
    };
    SendPlusCount(steps, directions);
    std::vector<int> freq = GetFreqCount(steps);
    qDebug()<<freq[0]<<","<<freq[1]<<","<<freq[2]<<","<<freq[3];
    SendFreqCount(freq);
    SendMove();
}

void Client::on_readButton_clicked()
{
    ui->state->setText(messenger->readMoveState());
}
//1  50.78  57.82
//2  63.76 62.79
//3  53.87 48.87
//4  40.68 32.69

void Client::SendPath(std::vector<std::vector<int> > &steps){
    double i = 1.0;
    for(std::vector<int>& step : steps){
        //step为每跟杆每一步走多少个脉冲
        std::vector<QString> directions = {
            step[0] > 0 ? "1" : "0",
            step[1] > 0 ? "1" : "0",
            step[2] > 0 ? "1" : "0",
            step[3] > 0 ? "1" : "0"
        };
        SendPlusCount(step, directions);
        std::vector<int> freq = GetFreqCount(step);
        SendFreqCount(freq);
        SendMove();
//        QThread::msleep(200);
        messenger->waitForNextStep();
        ui->progressBar->setValue(i * 100.0 / steps.size());
        ++i;
    }
}
#include <QFileDialog>
void Client::on_importPath_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, "ImportFile", "file", "(*.csv)");
    QFile File(fileName);
    if(!File.open(QIODevice::ReadOnly|QFile::Text))
        return;
    std::vector<std::vector<double>>res;
    QTextStream job(&File);
    QString line;
    line = job.readLine();
    while(!line.isEmpty()){
        QStringList slist = line.split(",");
        std::vector<double>cur;
        for(QString& val : slist)
            cur.push_back(val.toDouble());
//        qDebug()<<cur[0]<<","<<cur[1]<<","<<cur[2]<<","<<cur[3];
        res.push_back(cur);
        line = job.readLine();
    }
    File.close();
    ui->textBrowser->clear();
    path.clear();
    for(size_t i = 1;i < res.size();++i){
        QString lineText;
        std::vector<int>step;
        for(size_t j = 0;j < res[i].size();++j){
            int plusCount = DistanceToPlusCount(res[i][j] - res[i - 1][j]);
            if(plusCount > DistanceToPlusCount(10)){
                ui->textBrowser->append(QString::fromLocal8Bit("检测到步长大于10mm."));
                return;
            }
            step.push_back(plusCount);
            lineText.append(QString::number(plusCount) + " , ");
        }
        ui->textBrowser->append(lineText);
        path.push_back(step);
    }
}

void Client::on_startPath_clicked()
{
    if(path.empty())
        return;
    SendPath(path);
}
